﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;

namespace Engine
{
	class CPlayer
	{
		private int		m_iStartX;
		private int		m_iStartY;
		private int		m_iPosX;
		private int		m_iPosY;
		private int		m_iStamina;		//Used for remaining player strength
		private int		m_iPoints;		//Points earned by player

		//Stats
		private int		m_iMoves;
		private int		m_iStaminaUsed;
		private int		m_iKicks;
		
		//All individual bitmaps
		private Bitmap	m_bmpPlayerImage;
		private Bitmap	m_bmpPlayerAnimUp;
		private Bitmap	m_bmpPlayerAnimFall;
		private Bitmap	m_bmpPlayerAnimRight;
		private Bitmap	m_bmpPlayerAnimLeft;

		//Animations (NOTE: Player animations once where part of the animation core timer, this however caused lags and other strange behaviour)
		private CAnimationObj	m_oAnimObj;

		public CPlayer(int iPlayerTemplateID, bool bDebug = false)
		{
			switch(iPlayerTemplateID)
			{
				case 1 :
					m_bmpPlayerImage		= new Bitmap(Properties.Resources.P1_small, new Size(Const.GRID_DIM, Const.GRID_DIM));
					m_bmpPlayerAnimUp		= new Bitmap(Properties.Resources.P1_anim_climb);
					m_bmpPlayerAnimFall		= new Bitmap(Properties.Resources.P1_anim_fall);
					m_bmpPlayerAnimRight	= new Bitmap(Properties.Resources.P1_anim_climb);
					m_bmpPlayerAnimLeft		= new Bitmap(Properties.Resources.P1_anim_climb);
					break;
				case 2 :
					m_bmpPlayerImage		= new Bitmap(Properties.Resources.P2_small, new Size(Const.GRID_DIM, Const.GRID_DIM));
					m_bmpPlayerAnimUp		= new Bitmap(Properties.Resources.P2_anim_climb);
					m_bmpPlayerAnimFall		= new Bitmap(Properties.Resources.P2_anim_fall);
					m_bmpPlayerAnimRight	= new Bitmap(Properties.Resources.P2_anim_climb);
					m_bmpPlayerAnimLeft		= new Bitmap(Properties.Resources.P2_anim_climb);
					break;
				case 3 :
					m_bmpPlayerImage		= new Bitmap(Properties.Resources.P3_small, new Size(Const.GRID_DIM, Const.GRID_DIM));
					m_bmpPlayerAnimUp		= new Bitmap(Properties.Resources.P3_anim_climb);
					m_bmpPlayerAnimFall		= new Bitmap(Properties.Resources.P3_anim_fall);
					m_bmpPlayerAnimRight	= new Bitmap(Properties.Resources.P3_anim_climb);
					m_bmpPlayerAnimLeft		= new Bitmap(Properties.Resources.P3_anim_climb);
					break;
				case 4 :
					m_bmpPlayerImage		= new Bitmap(Properties.Resources.P4_small, new Size(Const.GRID_DIM, Const.GRID_DIM));
					m_bmpPlayerAnimUp		= new Bitmap(Properties.Resources.P4_anim_climb);
					m_bmpPlayerAnimFall		= new Bitmap(Properties.Resources.P4_anim_fall);
					m_bmpPlayerAnimRight	= new Bitmap(Properties.Resources.P4_anim_climb);
					m_bmpPlayerAnimLeft		= new Bitmap(Properties.Resources.P4_anim_climb);
					break;
			}

			if(bDebug)	//For debugging, players should have unlimited stamina
				m_iStamina = -1;
			else
				m_iStamina = 0;

			m_iPoints		= 0;
			m_iMoves		= 0;
			m_iStaminaUsed	= 0;
			m_iKicks		= 0;
		}

		//Correctly dispose all resources when destroying player
		//@ KR / 2014.05.20
		public void Destroy()
		{
			m_bmpPlayerImage.Dispose();
			m_bmpPlayerAnimUp.Dispose();
			m_bmpPlayerAnimFall.Dispose();
			m_bmpPlayerAnimRight.Dispose();
			m_bmpPlayerAnimLeft.Dispose();
		}

//////////////////////////////////////////////////////////////////////////////////////////////////////
////////// START POS SET AND GET

		//Set players start position on world
		//@ KR / 2014.05.20
		public void SetStartPos(int iX, int iY)
		{
			m_iStartX = iX;
			m_iStartY = iY;
		}
		//Get players start position
		//@ KR / 2014.05.20
		public void GetStartPos(ref int iX, ref int iY)
		{
			iX = m_iStartX;
			iY = m_iStartY;
		}

//////////////////////////////////////////////////////////////////////////////////////////////////////
////////// CURRENT POS SET AND GET

		//Set players position on world
		// - Set pixel based pos if AnimObj is valid
		//@ KR / 2014.05.20
		public void SetPos(int iX, int iY)
		{
			m_iPosX = iX;
			m_iPosY = iY;

			if(m_oAnimObj != null)
				m_oAnimObj.SetPos(iX, iY);
		}
		//Get players position
		//@ KR / 2014.05.20
		public void GetPos(ref int iX, ref int iY)
		{
			iX = m_iPosX;
			iY = m_iPosY;
		}

//////////////////////////////////////////////////////////////////////////////////////////////////////
////////// STAMINA

		//Get players stamina
		//@ KR / 2014.05.21
		public int GetStamina()
		{
			return m_iStamina;
		}

		//Set players stamina
		//@ KR / 2014.07.08
		public void SetStamina(int iValue)
		{
			m_iStamina = iValue;
		}

		//Add players stamina
		// - Ensures player is not in unlimited mode
		//@ KR / 2014.06.28
		public void AddStamina(int iStamina)
		{
			if(m_iStamina >= 0)
				m_iStamina += iStamina;
		}

		//Remove amount of stamina from player but prevent going below 0
		// - Return used stamina (in regard of available and cheat)
		//@ KR / 2014.07.08
		public int UseStamina(int iValue)
		{
			int iUsed = 0;

			if(m_iStamina > 0)
			{
				m_iStamina -= iValue;
				iUsed		= iValue;

				if(m_iStamina < 0)
				{
					iUsed += m_iStamina;
					m_iStamina = 0;
				}
			}

			return iUsed;
		}

//////////////////////////////////////////////////////////////////////////////////////////////////////
////////// POINTS

		//Add points to player account
		//@ KR / 2014.06.24
		public void AddPoints(int iPoints)
		{
			m_iPoints += iPoints;
		}

		//Remove points from player account
		//@ KR / 2014.07.09
		public void RemovePoints(int iPoints)
		{
			if(m_iPoints != -1)
			{
				m_iPoints -= iPoints;		

				if(m_iPoints < 0)
					m_iPoints = 0;
			}
		}

		//Add points to player account
		//@ KR / 2014.06.24
		public int GetPoints()
		{
			return m_iPoints;
		}

//////////////////////////////////////////////////////////////////////////////////////////////////////
////////// PLAYER MOVEMENT

		//Move right
		// - Returns false if movement can not be performed
		// - Ensure stamina allows movement at caller site
		//@ KR / 2014.05.21
		public bool MoveRight(int iCostIndex)
		{
			if(m_oAnimObj == null)			//Player can not performe any movement if its animation object is not valid
				return false;

			if(m_oAnimObj.IsRunning())		//Player can not move until previous move is complete
				return false;

			//Prevent from moving beyong the border
			if(m_iPosX+1 < Const.GRIDS_XAXIS)
			{
				m_iPosX++;
				m_iMoves++;
				m_iStaminaUsed += UseStamina(iCostIndex);

				m_oAnimObj.SetAnimation((Bitmap)m_bmpPlayerAnimRight.Clone(), 4, Const.ANIM_RIGHT, false);
				return true;		
			}
			return false;	
		}

		//Move left
		// - Returns false if movement can not be performed
		// - Ensure stamina allows movement at caller site
		//@ KR / 2014.05.21
		public bool MoveLeft(int iCostIndex)
		{
			if(m_oAnimObj == null)			//Player can not performe any movement if its animation object is not valid
				return false;

			if(m_oAnimObj.IsRunning())		//Player can not move until previous move is complete
				return false;

			//Prevent from moving beyong the border
			if(m_iPosX-1 >= 0)
			{
				m_iPosX--;
				m_iMoves++;
				m_iStaminaUsed += UseStamina(iCostIndex);

				m_oAnimObj.SetAnimation((Bitmap)m_bmpPlayerAnimLeft.Clone(), 4, Const.ANIM_LEFT, false);
				return true;
			}
			return false;	
		}

		//Move up
		// - Returns false if movement can not be performed
		// - Ensure stamina allows movement at caller site
		//@ KR / 2014.05.21
		public bool MoveUp(int iCostIndex)
		{
			if(m_oAnimObj == null)			//Player can not performe any movement if its animation object is not valid
				return false;

			if (m_oAnimObj.IsRunning())		//Player can not move until previous move is complete
				return false;

			//Prevent from moving beyond the border
			if(m_iPosY-1 >= 0)
			{
				//Move along y axis (BEWARE: y axis starts with 0 as topmost pos)
				m_iPosY--;
				m_iMoves++;
				m_iStaminaUsed += UseStamina(iCostIndex);

				m_oAnimObj.SetAnimation((Bitmap)m_bmpPlayerAnimUp.Clone(), 4, Const.ANIM_UP, false);
				return true;
			}
			return false;	
		}

		//Free fall
		// - Returns false if movement can not be performed
		// - Will ensure stamina can not fall below 0 (when kicked from edge)
		//@ KR / 2014.05.27 (revised)
		public bool FreeFall(int iCostIndex, bool bKicked)
		{
			if(m_oAnimObj == null)			//Player can not performe any movement if its animation object is not valid
				return false;

			if (m_oAnimObj.IsRunning())		//Player can not move until previous move is complete
				return false;

			if (m_iPosY + 1 < Const.GRIDS_YAXIS)
			{
				m_iPosY++; //Move along y axis (BEWARE: y axis starts with 0 as topmost pos)
				m_iMoves++;
				if(bKicked)
					m_iStaminaUsed += UseStamina(iCostIndex);

				m_oAnimObj.SetAnimation((Bitmap)m_bmpPlayerAnimFall.Clone(), 2, Const.ANIM_DOWN, false);
				return true;
			}
			return false;
		}

		//Is player currently in animated condition?
		//@ KR / 2014.06.28
		public bool IsAnimated()
		{
			return m_oAnimObj.IsRunning();
		}

//////////////////////////////////////////////////////////////////////////////////////////////////////
////////// ANIM OBJECT ACCESS

		//Register animation object to animation core
		//@ KR / 2014.05.21
		public void RegAnimObj()
		{
			if(m_oAnimObj == null)
			{
				m_oAnimObj = new CAnimationObj((Bitmap)m_bmpPlayerImage.Clone(), m_iPosX, m_iPosY);
				m_oAnimObj.SetTickOffset(1);
				CAnimationCore.SetAnimObj(m_oAnimObj);
			}
		}

		//Set animation object to null
		//@ KR / 2014.06.29
		public void ResetAnimObj()
		{
			if(m_oAnimObj != null)
				m_oAnimObj = null;
		}

		//Get player idle image
		//@ KR / 2014.07.08
		public Bitmap GetImage()
		{
			return m_bmpPlayerImage;
		}

//////////////////////////////////////////////////////////////////////////////////////////////////////
////////// STATS

		//Get player moves count and reset
		//@ KR / 2014.07.08
		public int GetMoveCount()
		{
			int iReturn = m_iMoves;
			m_iMoves = 0;
			return iReturn;
		}

		//Get player stamina used and reset
		//@ KR / 2014.07.08
		public int GetStaminaUsedCount()
		{
			int iReturn = m_iStaminaUsed;
			m_iStaminaUsed = 0;
			return iReturn;
		}

		//Get player kicks and reset
		//@ KR / 2014.07.08
		public int GetKicksCount()
		{
			int iReturn = m_iKicks;
			m_iKicks = 0;
			return iReturn;
		}

		//Increase kick count (kick only happens outside of own class)
		//@ KR / 2014.07.08
		public void IncKicks()
		{
			m_iKicks++;
		}
	}
}
